package socket.client_socket;

import org.junit.jupiter.api.Test;

import java.io.*;
import java.net.*;
import java.util.Arrays;
import java.util.List;

public class Run_01 {
    /**
     * 从服务器读取
     */
    @Test
    public void demo_01() {
        try(Socket socket = new Socket("time.nist.gov", 13)) {
            // 设置超时
            socket.setSoTimeout(15000);
            StringBuilder buffer = new StringBuilder();
            InputStreamReader reader = new InputStreamReader(socket.getInputStream(), "ASCII");
            for(int c = reader.read(); c != -1; c = reader.read()) {
                buffer.append((char) c);
            }
            System.out.println(buffer);
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 向服务器发送
     */
    @Test
    public void demo_02() {
        try (Socket socket = new Socket("dict.org", 2628)) {
            socket.setSoTimeout(15000);
            OutputStream outputStream = socket.getOutputStream();
            Writer writer = new OutputStreamWriter(outputStream, "UTF-8");
            writer.flush();

        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 构造但不连接
     */
    @Test
    public void demo_03() {
        Socket socket = new Socket();
        SocketAddress address = new InetSocketAddress("time.nist.gov", 13);
        try {
            // 填入socket选项
            //socket.connect(address);
            socket.connect(address, 15000);
            StringBuilder buffer = new StringBuilder();
            InputStreamReader reader = new InputStreamReader(socket.getInputStream(), "ASCII");
            for(int c = reader.read(); c != -1; c = reader.read()) {
                buffer.append((char) c);
            }
            System.out.println(buffer);
        } catch (IOException e) {
            System.err.println(e);
        } finally {
            try {
                socket.close();
            } catch (IOException e) {
                System.err.println(e);
            }
        }
    }

    /**
     * socket 地址
     *
     * SocketAddress类表示一个连接端点。是一个空的抽象类，当前只支持TCP/IP Socket。
     * 实际使用的地址都是InetSocketAddress的实例。
     * SocketAddress的主要用途是为暂时的socket的连接信息提供一个方便的存储，即使最初的sockets已断开并被垃圾回收，
     * 这些信息可以重用来创建新的Socket。为此Socket类提供了两个返回SocketAddress对象的方法：
     * getRemoteSocketAddress() 返回所连接系统的地址
     * getLocalSocketAddress() 返回发起连接的地址
     * 如果Socket尚未连接，两个方法都返回null。
     */
    @Test
    public void demo_04() {
        try {
            Socket socket = new Socket("www.baidu.com", 80);
            SocketAddress baidu = socket.getRemoteSocketAddress();
            socket.close();

            Socket socket2 = new Socket();
            socket2.connect(baidu);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    /**
     * 代理服务器
     */
    @Test
    public void demo_05() {
        InetSocketAddress proxyAddress = new InetSocketAddress("45.76.211.108", 8888);
        Proxy proxy = new Proxy(Proxy.Type.SOCKS, proxyAddress);
        Socket s = new Socket(proxy);

        InetSocketAddress remote = new InetSocketAddress("wwww.baidu.com", 80);
        try {
            s.connect(remote);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取socket信息
     *
     * 远程地址 getInetAddress()
     * 远程端口 getPort()
     * 本地地址 getLocalAddress()
     * 本地端口 getLocalPort()
     *
     * 运行结果:
     * Connected to www.oreilly.com/23.42.95.13 on port 80 from port 13689 of /10.26.9.183
     * Connected to www.oreilly.com/23.42.95.13 on port 80 from port 13691 of /10.26.9.183
     * Connected to www.baidu.com/220.181.111.188 on port 80 from port 13692 of /10.26.9.183
     */
    @Test
    public void demo_06() {
        List<String> hostList = Arrays.asList("www.oreilly.com", "www.oreilly.com", "www.baidu.com");
        for (String host : hostList) {
            Socket socket = null;
            try {
                socket = new Socket(host, 80);
            } catch (IOException e) {
                e.printStackTrace();
            }
            System.out.println("Connected to " + socket.getInetAddress()
                + " on port " + socket.getPort() + " from port "
                + socket.getLocalPort() + " of "
                + socket.getLocalAddress());
        }
    }

    /**
     * 关闭还是连接
     *
     * 如果socket关闭，isClosed()方法会返回true，否则返回false。如果你不确定一个socket的状态，可以用这个方法进行检查，而不要
     * 抛出IOException异常。
     * 不过这不是一个完全的方法。如果socket从一开始就从未连接，isClosed()也返回false，尽管Socket实际上根本没有打开过。
     *
     * Socket类还有个isConnected()方法，地图、他并不是指示Socket当前是否连接到一个远程主机。
     * 实际上，他会指出Socket是否从未连接过一个远程主机。如果这个Sokcet确实能够连接到远程主机，isConnected()会返回true，
     * 即使这个socket已经关闭了。要查看一个Socket当前是否打开，需检查两个条件：
     * isConnected()要返回true
     * isClosed()要返回false
     * boolean connected = socket.isConnected() && !socket.isClosed()
     */
    @Test
    public void demo_07() {
        Socket socket = new Socket();
        InetSocketAddress address = new InetSocketAddress("www.baidu.com", 80);
        System.out.println("从未连接过,socket 是否已经关闭：" + socket.isClosed());
        try {
            socket.connect(address);
            System.out.println("关闭Socket");
            socket.close();
            System.out.println("socket 是否已经关闭：" + socket.isClosed());
            System.out.println("是否能够连接到远程主机: " + socket.isConnected());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
